package partFour;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*本类用于练习暴力反射*/
public class TestViolentReflection {
    @Test
    public void getFields() throws Exception {
        //1.获取字节码对象
        Class<?> clazz = Person.class;
        //2.获取指定的私有属性，传入的是属性名，注意抛出异常
        clazz.getDeclaredField("name");
        //3.根据刚刚获取到的属性对象，查看属性的信息
        Field field = clazz.getDeclaredField("name");
        System.out.println(field);//private java.lang.String cn.review.Person.name
        // 直接打印获取到的字段对象
        System.out.println(field.getType().getName());//java.lang.String
        System.out.println(field.getType());//class java.lang.String

        //4.设置属性的值
        //4.1需要指定到底是哪个对象的name属性设置值，没有对象就创建对象
        Object obj = clazz.newInstance(); //触发无参构造利用反射创建对象

        //4.2暴力反射需要设置私有可见权限
        field.setAccessible(true);


        //4.3通过字段对象给刚刚创建好的对象obj设置属性值为海绵宝宝
        //field就是我们刚刚捕获的name属性
        //set(m,n)--m是给哪个对象的name属性设置值，n是设置的值是什么
        field.set(obj,"海绵宝宝");

        //4.4打印查看刚刚设置的属性值
        //field.get(m)--field代表的就是Person类的name属性，m是查看哪个对象的这个属性值
        System.out.println(field.get(obj));//海绵宝宝
    }
    @Test
    public void getFie3() throws Exception {
        //1.获取字节码对象
        Class<?> clazz = Person.class;
        //2.根据获取到的属性对象，查看相关信息，比如属性的类型
        Field f = clazz.getDeclaredField("age");
        //3.根据获取到的属性对象，查看相关信息，比如属性的类型
        System.out.println(f.getType().getName());//int
        //4.操作：设置属性的值：一共需要三个元素：给哪个对象【1】的哪个属性【2】设置一个什么值【3】
        //4.1需要先指定给哪个对象的这个age属性设置值
        Object obj = clazz.newInstance();
        //4.2在给属性设置值之前，需要设置权限私有可见，否则报错
        f.setAccessible(true);
        //4.3通过刚刚获取到的age属性对象，给obj对象设置值
        f.set(obj,17);
        //4.4打印查看刚刚的属性值是否设置成功
        System.out.println(f.get(obj));//17
    }
    //3.创建单元测试方法：通过暴力反射获取与执行Person类的私有方法
    @Test
    public void getFunction2() throws Exception {
        //1.获取字节码对象
        Class<?> clazz = Person.class;
        //2.可以通过字节码对象获取某一个指定的私有方法对象
        //如何确定要找哪一个方法？方法名+参数列表
        Method method = clazz.getDeclaredMethod("save", int.class, String.class);

        /*在执行私有的方法之前，需要设置私有可见的权限*/
        method.setAccessible(true);
        //3.在执行获取到的方法前，需要先指定给哪个对象做这个save()操作
        //3.1没有对象就创建对象
        Object obj = clazz.newInstance();
        //3.2通过刚刚获取到的方法对象method给指定的对象obj做操作，注意传参
        method.invoke(obj,666,"哈哈哈");

        System.out.println(method);//save()...666哈哈哈
    }
}